# -*- coding: utf-8 -*-

import cv2
import math
import struct
import sys
import time
import os
import re
import traceback

starttime = time.time()

argv = sys.argv
#argv = ["decode.py","source/5dc2352297dda1448cee4b58f7b7d0a20df4860f.png"]
#argv = ["decode.py","source/TieBa7efcf1b62d4.jpg"]

# l=[0,"500K","1M","1.5M","2M"]
# MODE=parseInt(document.getElementById("select").value);
# document.getElementById("info1").innerHTML="建议里图大小：小于"+l[MODE]


#未输入文件名时输出帮助信息
if(len(argv) != 2):
    print("用法: dewytk [filename]")
    print("将在执行路径生成图片")
    endtime = time.time()
    print('[!-1]耗时', str(round(endtime - starttime, 2)),'秒')
    exit(-1)
else:
    imgfile = argv[1]

try:
    img = cv2.imread(imgfile,cv2.IMREAD_UNCHANGED)      #图片本体
    imgdata = []                                        #用字典表示像素点
    rawdata = dict()                                    #临时的字典
    
    print("图像的形状,返回一个图像的(行数,列数,通道数):",img.shape)

    mode = 4                   #图片解密模式

    #将图片读取为字典的列表形式，同时判断是否为坦克
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            p = img[i][j]#返回的是每一个像素点的RGB
            #BGRA
            rawdata = dict()
            rawdata['R'] = p[0]
            rawdata['G'] = p[1]
            rawdata['B'] = p[2]
            imgdata.append(rawdata)#像素点的RGB合集（列表里面存集合）
            if(i == 0 and j == 0):#mode存储在第一个像素点的红色通道中
                #从第一个像素点的红色通道中读取解密模式
                mode = p[0] % 8
                if (mode <= 0 or mode >4):
                    endtime = time.time()
                    print('[!-3]解密模式提取失败 耗时', str(round(endtime - starttime, 2)),'秒')
                    print('删除解密失败的文件')
                    os.remove(imgfile)
                    exit(-3)

    # 开始从RGB三个通道中提取数据
    aa = math.ceil(3*mode/8)         #读取三个通道后字节数量为3*mode（被隐藏文件的大小）,aa为需要转化为字节的次数
    n = img.size                     #图片大小（像素点个数）
    j = 0                            #文件本体内容的字节序号
    k = ""                           #读取的比特串
    current_pixel_index = 1          #像素点的序号
    word = ""                        #数据内容
    blist = []                       #字节数组，存储提取出的字节流
    blength = 0                      #字节流长度
    #提取文件名  格式：长度(字节)\u0001文件名\u0001文件类型
    #n'<=n*mode/8
    while(current_pixel_index < n and (len(word) == 0 or ord(word[-1])>0 )):
        k = k+str(bin(imgdata[current_pixel_index]['B'] + 256))[-mode:]#怎么存的怎么读
        k = k+str(bin(imgdata[current_pixel_index]['G'] + 256))[-mode:]#二进制字符串的高位用0填充
        k = k+str(bin(imgdata[current_pixel_index]['R'] + 256))[-mode:]
        current_pixel_index = current_pixel_index +1
        for i in range(0,aa):
            if(len(k) >= 8 and (len(word) == 0 or ord(word[-1]) > 0)):
                word = word + chr(int(k[0:8],2))
                k = k[8:]            #读取完8比特即1字节后，k向后移动8比特

    #处理文件信息乱码的情况 文件信息不符合定义的格式（采用正则表达式）
    if(re.match(r'^(.)+\x01(.)+\x01(.)+$',word,flags=0) is None):
        endtime = time.time()
        print('[!-2]文件信息提取失败 耗时', str(round(endtime - starttime, 2)), '秒')
        print('删除解密失败的文件')
        os.remove(imgfile)
        exit(-2)

    blength = int(word.split(chr(1))[0])
    blist = []

    if(len(k) >= 8 and j < blength):
        blist.append(int(k[0:8],2))
        k = k[8:]
        j = j + 1
    #提取文件内容
    while (current_pixel_index < n and j < blength):
        k = k+str(bin(imgdata[current_pixel_index]['B'] + 256))[-mode:]
        k = k+str(bin(imgdata[current_pixel_index]['G'] + 256))[-mode:]
        k = k+str(bin(imgdata[current_pixel_index]['R'] + 256))[-mode:]
        current_pixel_index = current_pixel_index +1
        for i in range(0,aa):
            if(len(k) >= 8 and j<blength):
                blist.append(int(k[0:8],2))
                k = k[8:]
                j = j + 1

    target = "target/" + str(word.split(chr(1))[1])

    a = 1
    with open(target, 'wb')as fp:
        for x in blist:
            a = struct.pack('B', x)
            fp.write(a)
    endtime = time.time()
    print("已经向源文件 " + str(word.split(chr(1))[1]) + "\t写入了 " + str(word.split(chr(1))[0]) + "\t字节,耗时 " + str(round(endtime - starttime, 2))+ "\t秒")
    exit(0)
    pass
except Exception:
    traceback.print_exc()
    endtime = time.time()
    print("[!-5]" + '耗时', str(round(endtime - starttime, 2)),'秒')
    exit(-5)
    pass
